package com.dgut.lab.security;

import com.dgut.lab.entity.User;
import com.dgut.lab.service.UserService;
import lombok.SneakyThrows;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Objects;

public class DgutOAuth2AuthenticationProvider implements AuthenticationProvider {
    private UserService userService;
    private static final String ACCESS_TOKEN_API_URI = "https://cas.dgut.edu.cn/ssoapi/v2/checkToken?token={token}&appid={appid}&appsecret={appsecret}&userip={userip}";
    private static final String USER_INFO_URI = "https://cas.dgut.edu.cn/oauth/getUserInfo?access_token={access_token}&openid={openid}";
    private static final RestTemplate rest = new RestTemplate();
    private static final String APPID = "javaee";
    private static final String APPSECRET = "b3b52e43ccfd";

    public DgutOAuth2AuthenticationProvider(UserService userService) {
        this.userService = userService;
    }


    @SneakyThrows
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//        System.out.println("进入");
        // 用户认证前，构造一个GiteeOAuth2LoginAuthenticationToken
        DgutOAuth2LoginAuthenticationToken authenticationToken = (DgutOAuth2LoginAuthenticationToken) authentication;
        // 通过码云API获取access_token
        Map result = getAccessTokenAndOpenId(authenticationToken.getToken());
        // 通过码云API获取Gitee授权用户的资料
        Map<String, Object> userInfo = getUserInfo(result);
        // 认证成功后，重新生成Authentication
        return createSuccessAuthentication(Objects.requireNonNull(userInfo), authenticationToken.getRequest());
    }

    private Map<String,Object> getAccessTokenAndOpenId(String token) throws UnknownHostException {
        InetAddress ip4 = Inet4Address.getLocalHost();
//        System.out.println(ip4.getHostAddress());
        URI uri = UriComponentsBuilder.fromUriString(ACCESS_TOKEN_API_URI)
                .encode()
                .buildAndExpand(token,APPID,APPSECRET,ip4).toUri();

        // header不加User-Agent就403 Forbidden
        RequestEntity<Void> requestEntity = RequestEntity.post(uri)
                .header("User-Agent", "Mozilla/5.0")
                .build();
        ResponseEntity<String> response = rest.exchange(requestEntity, String.class);
        Map<String, Object> resultMap = new JacksonJsonParser().parseMap(response.getBody());
        return resultMap;
    }

    private Map<String, Object> getUserInfo(Map<String,Object> map) {
        String accessToken = (String) map.get("access_token");
        String openId = (String) map.get("openid");

        URI uri = UriComponentsBuilder.fromUriString(USER_INFO_URI)
                .encode()
                .buildAndExpand(accessToken,openId).toUri();
        // header不加User-Agent就403 Forbidden
        RequestEntity<Void> requestEntity = RequestEntity.post(uri)
                .header("User-Agent", "Mozilla/5.0")
                .build();
        ResponseEntity<String> response = rest.exchange(requestEntity, String.class);
//        System.out.println(response);
        if(response == null)
            return null;
//        System.out.println("response:"+response);
        String result = response.getBody();
//        System.out.println("result+"+result);
        return new JacksonJsonParser().parseMap(result);
    }

    private Authentication createSuccessAuthentication(Map<String,Object> userInfo, HttpServletRequest request) {
        SecurityUserDetails securityUserDetails = new SecurityUserDetails();
        User user = userService.queryByUsername(((String) userInfo.get("username")));
        if(user==null){
            User userAdd = new User();
            userAdd.setUsername((String) userInfo.get("username"));
            userAdd.setName((String) userInfo.get("name"));
            userAdd.setDepartment((String)userInfo.get("faculty_title"));
            userAdd.setAccountNonExpired(1);
            userAdd.setAccountNonLocked(1);
            userAdd.setCredentialsNonExpired(1);
            userAdd.setEnabled(1);
            userAdd.setRole("STUDENT");
            user = userService.saveUser(userAdd);
        }
        securityUserDetails.setUserInfo(user);
        DgutOAuth2LoginAuthenticationToken authenticationToken = new DgutOAuth2LoginAuthenticationToken(securityUserDetails, AuthorityUtils.createAuthorityList("ROLE_STUDENT"));
        AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
        authenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
        return authenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return DgutOAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
